#include "ChivoxCfg.hpp"
#include <assert.h>

#define ASSERT(cond, msg) {\
    if (!cond) printf("%s\n", msg); \
    fflush(stdout); \
    assert(cond); \
}

ChivoxCfg::ChivoxCfg() {
    //printf("ChivoxCfg()\n");
    this->_parent = NULL;
    this->_json = NULL;
}

ChivoxCfg::~ChivoxCfg(){
    printf("~ChivoxCfg()\n");
    if (!this->_parent) {
        cJSON_Delete(this->_json);
        this->_json = NULL;
    } else {
        // `_parent` and `_json` is weak reference, don't delete them.
    }
}

ChivoxCfg *ChivoxCfg::create() {
    printf("ChivoxCfg::create()\n");
    ChivoxCfg *dict = new ChivoxCfg();
    dict->_parent = NULL;
    dict->_json = cJSON_CreateObject();
    return dict;
}

ChivoxCfg *ChivoxCfg::BeginDict(const char *key) {
    printf("ChivoxCfg::BeginDict(%s)\n", key?key:"");
    ChivoxCfg *dict = new ChivoxCfg();
    dict->_parent = this;
    dict->_json = cJSON_CreateObject();
    if (this->_json->type == cJSON_Array) {
        cJSON_AddItemToArray(this->_json, dict->_json);
    } else {
        ASSERT(key, "key is null");
        cJSON_AddItemToObject(this->_json, key, dict->_json);
    }
    return dict;
}

ChivoxCfg *ChivoxCfg::BeginArr(const char *key) {
    printf("ChivoxCfg::BeginArr(%s)\n", key?key:"");
    ChivoxCfg *arr = new ChivoxCfg();
    arr->_parent = this;
    arr->_json = cJSON_CreateArray();
    if (this->_json->type == cJSON_Array) {
        cJSON_AddItemToArray(this->_json, arr->_json);
    } else {
        ASSERT(key, "key is null");
        cJSON_AddItemToObject(this->_json, key, arr->_json);
    }
    return arr;
}

ChivoxCfg *ChivoxCfg::End(const char *tag) {
    printf("ChivoxCfg::End(%s)\n", tag?tag:"");
    ChivoxCfg *parent = this->_parent;
    if (parent) {
        delete this;
        return parent;
    } else {
        return this;
    }
}

ChivoxCfg *ChivoxCfg::kvBool(const char *key, bool value) {
    ASSERT(this->_json->type == cJSON_Object, "json node not object");
    ASSERT(key, "key is null");
    cJSON_AddBoolToObject(this->_json, key, value);
    return this;
}

ChivoxCfg *ChivoxCfg::kvNumber(const char *key, double value) {
    ASSERT(this->_json->type == cJSON_Object, "json node not object");
    ASSERT(key, "key is null");
    cJSON_AddNumberToObject(this->_json, key, value);
    return this;
}

ChivoxCfg *ChivoxCfg::kvString(const char *key, const char *value) {
    ASSERT(this->_json->type == cJSON_Object, "json node not object");
    ASSERT(key, "key is null");
    cJSON_AddStringToObject(this->_json, key, value);
    return this;
}

ChivoxCfg *ChivoxCfg::vBool(bool value) {
    ASSERT(this->_json->type == cJSON_Array, "json node not array");
    cJSON *item = cJSON_CreateBool(value);
    cJSON_AddItemToArray(this->_json, item);
    return this;
}

ChivoxCfg *ChivoxCfg::vNumber(double value) {
    ASSERT(this->_json->type == cJSON_Array, "json node not array");
    cJSON *item = cJSON_CreateNumber(value);
    cJSON_AddItemToArray(this->_json, item);
    return this;

}

ChivoxCfg *ChivoxCfg::vString(const char *value) {
    ASSERT(this->_json->type == cJSON_Array, "json node not array");
    cJSON *item = cJSON_CreateString(value);
    cJSON_AddItemToArray(this->_json, item);
    return this;
}

char *ChivoxCfg::buildJsonString() {
    return cJSON_PrintUnformatted(this->_json);
}

char *ChivoxCfg::buildFormatJsonString() {
    return cJSON_Print(this->_json);
}

